package sym.qrcode.style;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;

import sym.qrcode.encoder.ByteMatrix;
import sym.qrcode.encoder.Mosaic;
import sym.qrcode.encoder.MosaicMatrix;
import sym.qrcode.image.ImageMosaicMatrix;
import sym.qrcode.image.OutputImage;

public class RoundCornerStyle implements ImageGenerator {
	OutputImage outputMatrix;

	public final static int MARGIN = 4;

	public RoundCornerStyle(OutputImage outputMatrix) {
		this.outputMatrix = outputMatrix;
	}

	@Override
	public BufferedImage getFinalImage() {
		// TODO Auto-generated method stub
		int finalWidth = outputMatrix.getMaxImageWidth() + 2 * MARGIN;
		int finalHeight = outputMatrix.getMaxImageHeight() + 2 * MARGIN;
		int scale = outputMatrix.getScale();

		BufferedImage resultImage = new BufferedImage(finalWidth, finalHeight,
				BufferedImage.TYPE_INT_RGB);
		Graphics g = resultImage.getGraphics();
		g.setColor(Color.white);
		g.fillRect(0, 0, finalWidth, finalHeight);

		MosaicMatrix m = outputMatrix.getQrcode().getMosaicMatrix();
		ByteMatrix matrix = outputMatrix.getQrcode().getMatrix();
		for (int i = 0; i < m.getWidth(); i++) {
			for (int j = 0; j < m.getHeight(); j++) {
				if (!isImage(i, j)) {
					if (matrix.get(i, j) != 0) {
						if (isLeftUp(i, j)) {
							for (int p = 0; p < scale / 2; p++) {
								for (int q = 0; q < scale / 2; q++) {
									int flag = isInCircle(p, q, scale / 2,
											scale / 2, scale / 2);
									if (flag == 1) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.black.getRGB());
									} else if (flag == 2) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									} else {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.white.getRGB());
									}
								}
							}
							// for (int p = 0; p < scale / 2; p++) {
							// for (int q = 0; q < scale / 2; q++) {
							// if (p < scale / 4 && q < scale / 4)
							// continue;
							// if (p == 0)
							// resultImage.setRGB(MARGIN + i * scale
							// + p, MARGIN + j * scale + q,
							// Color.RED.getRGB());
							// else if (q == 0)
							// resultImage.setRGB(MARGIN + i * scale
							// + p, MARGIN + j * scale + q,
							// Color.RED.getRGB());
							// else
							// resultImage.setRGB(MARGIN + i * scale
							// + p, MARGIN + j * scale + q,
							// Color.BLACK.getRGB());
							// }
							// }
						} else if (isLeft(i, j)) {
							for (int p = 0; p < scale / 2; p++) {
								for (int q = 0; q < scale / 2; q++) {
									if (p == 0)
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									else
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.black.getRGB());
								}
							}
						} else if (isUp(i, j)) {
							for (int p = 0; p < scale / 2; p++) {
								for (int q = 0; q < scale / 2; q++) {
									if (q == 0)
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									else
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.black.getRGB());
								}
							}
						} else {
							for (int p = 0; p < scale / 2; p++) {
								for (int q = 0; q < scale / 2; q++) {
									resultImage.setRGB(MARGIN + i * scale + p,
											MARGIN + j * scale + q,
											Color.black.getRGB());
								}
							}
						}

						if (isRightUp(i, j)) {
							for (int p = scale / 2; p < scale; p++) {
								for (int q = 0; q < scale / 2; q++) {
									int flag = isInCircle(p, q, scale / 2,
											scale / 2, scale / 2);
									if (flag == 1) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.black.getRGB());
									} else if (flag == 2) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									} else {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.white.getRGB());
									}
								}
							}
							// for (int p = scale / 2; p < scale; p++) {
							// for (int q = 0; q < scale / 2; q++) {
							// if (p >= 3 * scale / 4 && q < scale / 4)
							// continue;
							// if (p == scale - 1)
							// resultImage.setRGB(MARGIN + i * scale
							// + p, MARGIN + j * scale + q,
							// Color.RED.getRGB());
							// else if (q == 0)
							// resultImage.setRGB(MARGIN + i * scale
							// + p, MARGIN + j * scale + q,
							// Color.RED.getRGB());
							// else
							// resultImage.setRGB(MARGIN + i * scale
							// + p, MARGIN + j * scale + q,
							// Color.BLACK.getRGB());
							// }
							// }
						} else if (isRight(i, j)) {
							for (int p = scale / 2; p < scale; p++) {
								for (int q = 0; q < scale / 2; q++) {
									if (p == scale - 1)
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									else
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.black.getRGB());
								}
							}
						} else if (isUp(i, j)) {
							for (int p = scale / 2; p < scale; p++) {
								for (int q = 0; q < scale / 2; q++) {
									if (q == 0)
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									else
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.black.getRGB());
								}
							}
						} else {
							for (int p = scale / 2; p < scale; p++) {
								for (int q = 0; q < scale / 2; q++) {
									resultImage.setRGB(MARGIN + i * scale + p,
											MARGIN + j * scale + q,
											Color.black.getRGB());
								}
							}
						}

						if (isLeftBottom(i, j)) {
							for (int p = 0; p < scale / 2; p++) {
								for (int q = scale / 2; q < scale; q++) {
									int flag = isInCircle(p, q, scale / 2,
											scale / 2, scale / 2);
									if (flag == 1) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.black.getRGB());
									} else if (flag == 2) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									} else {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.white.getRGB());
									}
								}
							}
							// for (int p = 0; p < scale / 2; p++) {
							// for (int q = scale / 2; q < scale; q++) {
							// if (p < scale / 4 && q >= 3 * scale / 4)
							// continue;
							// if (p == 0)
							// resultImage.setRGB(MARGIN + i * scale
							// + p, MARGIN + j * scale + q,
							// Color.RED.getRGB());
							// else if (q == scale - 1)
							// resultImage.setRGB(MARGIN + i * scale
							// + p, MARGIN + j * scale + q,
							// Color.RED.getRGB());
							// else
							// resultImage.setRGB(MARGIN + i * scale
							// + p, MARGIN + j * scale + q,
							// Color.BLACK.getRGB());
							// }
							// }
						} else if (isLeft(i, j)) {
							for (int p = 0; p < scale / 2; p++) {
								for (int q = scale / 2; q < scale; q++) {
									if (p == 0)
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									else
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.black.getRGB());
								}
							}
						} else if (isBottom(i, j)) {
							for (int p = 0; p < scale / 2; p++) {
								for (int q = scale / 2; q < scale; q++) {
									if (q == scale - 1)
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									else
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.black.getRGB());
								}
							}
						} else {
							for (int p = 0; p < scale / 2; p++) {
								for (int q = scale / 2; q < scale; q++) {
									resultImage.setRGB(MARGIN + i * scale + p,
											MARGIN + j * scale + q,
											Color.black.getRGB());
								}
							}
						}

						if (isRightBottom(i, j)) {
							for (int p = scale / 2; p < scale; p++) {
								for (int q = scale / 2; q < scale; q++) {
									int flag = isInCircle(p, q, scale / 2,
											scale / 2, scale / 2);
									if (flag == 1) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.black.getRGB());
									} else if (flag == 2) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									} else {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.white.getRGB());
									}
								}
							}
							// for (int p = scale / 2; p < scale; p++) {
							// for (int q = scale / 2; q < scale; q++) {
							// if (p >= 3*scale / 4 && q >= 3 * scale / 4)
							// continue;
							// if (p == scale - 1)
							// resultImage.setRGB(MARGIN + i * scale
							// + p, MARGIN + j * scale + q,
							// Color.RED.getRGB());
							// else if (q == scale - 1)
							// resultImage.setRGB(MARGIN + i * scale
							// + p, MARGIN + j * scale + q,
							// Color.RED.getRGB());
							// else
							// resultImage.setRGB(MARGIN + i * scale
							// + p, MARGIN + j * scale + q,
							// Color.BLACK.getRGB());
							// }
							// }
						} else if (isRight(i, j)) {
							for (int p = scale / 2; p < scale; p++) {
								for (int q = scale / 2; q < scale; q++) {
									if (p == scale - 1)
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									else
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.black.getRGB());
								}
							}
						} else if (isBottom(i, j)) {
							for (int p = scale / 2; p < scale; p++) {
								for (int q = scale / 2; q < scale; q++) {
									if (q == scale - 1)
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									else
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.black.getRGB());
								}
							}
						} else {
							for (int p = scale / 2; p < scale; p++) {
								for (int q = scale / 2; q < scale; q++) {
									resultImage.setRGB(MARGIN + i * scale + p,
											MARGIN + j * scale + q,
											Color.black.getRGB());
								}
							}
						}
					}
				}
			}
		}

		for (int i = 0; i < m.getWidth(); i++) {
			for (int j = 0; j < m.getHeight(); j++) {
				if (!isImage(i, j)) {
					if (matrix.get(i, j) == 0) {
						if (isWhiteLeftUp(i, j)) {
							for (int p = -1; p < scale / 2; p++) {
								for (int q = -1; q < scale / 2; q++) {
									int flag = isInCircle(p, q, scale / 2,
											scale / 2, scale / 2);
									if (flag == 2) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									} else if (flag == 0) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.black.getRGB());
									}
								}
							}
						}
						if (isWhiteRightUp(i, j)) {
							for (int p = scale / 2; p <= scale; p++) {
								for (int q = -1; q < scale / 2; q++) {
									int flag = isInCircle(p, q, scale / 2,
											scale / 2, scale / 2);
									if (flag == 2) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									} else if (flag == 0) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.black.getRGB());
									}
								}
							}
						}
						if (isWhiteLeftBottom(i, j)) {
							for (int p = -1; p < scale / 2; p++) {
								for (int q = scale / 2; q <= scale; q++) {
									int flag = isInCircle(p, q, scale / 2,
											scale / 2, scale / 2);
									if (flag == 2) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									} else if (flag == 0) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.black.getRGB());
									}
								}
							}
						}
						if (isWhiteRightBottom(i, j)) {
							for (int p = scale / 2; p <= scale; p++) {
								for (int q = scale / 2; q <= scale; q++) {
									int flag = isInCircle(p, q, scale / 2,
											scale / 2, scale / 2);
									if (flag == 2) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									} else if (flag == 0) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.black.getRGB());
									}
								}
							}
						}
					}
				}
			}
		}
		for (ImageMosaicMatrix m2 : outputMatrix.getMosaicList()) {
			for (int i2 = 0; i2 < m2.getWidth(); i2++)
				for (int j2 = 0; j2 < m2.getHeight(); j2++) {
					if (m2.getMatrix()[j2][i2].type == Mosaic.IMAGE) {
						for (int p = 0; p < scale; p++)
							for (int q = 0; q < scale; q++) {
								resultImage.setRGB(
										MARGIN + (m2.getX() + i2) * scale + p,
										MARGIN + (m2.getY() + j2) * scale + q,
										m2.getColorRGB(i2 * scale + p, j2
												* scale + q));
							}
					}
				}
		}
		return resultImage;
	}

	protected int isInCircle(int p, int q, int i, int j, int k) {
		// TODO Auto-generated method stub
		int r = (int) Math.sqrt((p - i) * (p - i) + (q - j) * (q - j));
		if (r == k)
			return 2;
		else if (r > k)
			return 0;
		else
			return 1;
	}

	protected boolean isUp(int i, int j) {
		// TODO Auto-generated method stub
                ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (j > 0) {
			if (m.get(i, j - 1) == 0 || isImage(i, j - 1))
				return true;
		} else
			return true;
		return false;
	}

	protected boolean isLeft(int i, int j) {
		// TODO Auto-generated method stub
		ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (i > 0) {
			if (m.get(i - 1, j) == 0 || isImage(i - 1, j))
				return true;
		} else
			return true;
		return false;
	}

	protected boolean isRightUp(int i, int j) {
		// TODO Auto-generated method stub
		ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (i < m.getWidth() - 1 && j > 0) {
			if ((m.get(i + 1, j) == 0 || isImage(i + 1, j))
					&& (m.get(i, j - 1) == 0 || isImage(i, j - 1))
					) {
				return true;
			}
		} else if (i < m.getWidth() - 1) {
			if (m.get(i + 1, j) == 0 || isImage(i + 1, j)) {
				return true;
			}
		} else if (j > 0) {
			if (m.get(i, j - 1) == 0 || isImage(i, j - 1)) {
				return true;
			}
		} else
			return true;
		return false;
	}

	protected boolean isWhiteRightBottom(int i, int j) {
		// TODO Auto-generated method stub
		ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (i < m.getWidth() - 1 && j < m.getHeight() - 1) {
			if ((m.get(i + 1, j) != 0 && !isImage(i + 1, j))
					&& (m.get(i, j + 1) != 0 && !isImage(i, j + 1))
					&& (m.get(i + 1, j + 1) != 0 && !isImage(i + 1, j + 1))) {
				return true;
			}
		}
		return false;
	}

	protected boolean isWhiteLeftBottom(int i, int j) {
		// TODO Auto-generated method stub
		ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (i > 0 && j < m.getHeight() - 1) {
			if ((m.get(i - 1, j) != 0 && !isImage(i - 1, j))
					&& (m.get(i, j + 1) != 0 && !isImage(i, j + 1))
					&& (m.get(i - 1, j + 1) != 0 && !isImage(i - 1, j + 1))) {
				return true;
			}
		}
		return false;
	}

	protected boolean isWhiteRightUp(int i, int j) {
		// TODO Auto-generated method stub
		ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (i < m.getWidth() - 1 && j > 0) {
			if ((m.get(i + 1, j) != 0 && !isImage(i + 1, j))
					&& (m.get(i, j - 1) != 0 && !isImage(i, j - 1))
					&& (m.get(i + 1, j - 1) != 0 && !isImage(i + 1, j - 1))) {
				return true;
			}
		}
		return false;
	}

	protected boolean isWhiteLeftUp(int i, int j) {
		// TODO Auto-generated method stub
		ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (i > 0 && j > 0) {
			if ((m.get(i - 1, j) != 0 && !isImage(i - 1, j))
					&& (m.get(i, j - 1) != 0 && !isImage(i, j - 1))
					&& (m.get(i - 1, j - 1) != 0 && !isImage(i - 1, j - 1))) {
				return true;
			}
		}
		return false;
	}

	protected boolean isRightBottom(int i, int j) {
		// TODO Auto-generated method stub
		ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (i < m.getWidth() - 1 && j < m.getHeight() - 1) {
			if ((m.get(i + 1, j) == 0 || isImage(i + 1, j))
					&& (m.get(i, j + 1) == 0 || isImage(i, j + 1))
					) {
				return true;
			}
		} else if (i < m.getWidth() - 1) {
			if (m.get(i + 1, j) == 0 || isImage(i + 1, j)) {
				return true;
			}
		} else if (j < m.getHeight() - 1) {
			if (m.get(i, j + 1) == 0 || isImage(i, j + 1)) {
				return true;
			}
		} else
			return true;
		return false;
	}

	protected boolean isBottom(int i, int j) {
		// TODO Auto-generated method stub
		ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (j < m.getHeight() - 1) {
			if (m.get(i, j + 1) == 0 || isImage(i, j + 1))
				return true;
		} else
			return true;
		return false;
	}

	protected boolean isLeftBottom(int i, int j) {
		// TODO Auto-generated method stub
		ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (i > 0 && j < m.getHeight() - 1) {
			if ((m.get(i - 1, j) == 0 || isImage(i - 1, j))
					&& (m.get(i, j + 1) == 0 || isImage(i, j + 1))
				) {
				return true;
			}
		} else if (i > 0) {
			if (m.get(i - 1, j) == 0 || isImage(i - 1, j)) {
				return true;
			}
		} else if (j < m.getHeight() - 1) {
			if (m.get(i, j + 1) == 0 || isImage(i, j + 1)) {
				return true;
			}
		} else
			return true;
		return false;
	}

	protected boolean isRight(int i, int j) {
		// TODO Auto-generated method stub
		ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (i < m.getWidth() - 1) {
			if (m.get(i + 1, j) == 0 || isImage(i + 1, j))
				return true;
		} else
			return true;
		return false;
	}

	protected boolean isLeftUp(int i, int j) {
		// TODO Auto-generated method stub
		ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (i > 0 && j > 0) {
			if ((m.get(i - 1, j) == 0 || isImage(i - 1, j))
					&& (m.get(i, j - 1) == 0 || isImage(i, j - 1))
					) {
				return true;
			}
		} else if (i > 0) {
			if (m.get(i - 1, j) == 0 || isImage(i - 1, j)) {
				return true;
			}
		} else if (j > 0) {
			if (m.get(i, j - 1) == 0 || isImage(i, j - 1)) {
				return true;
			}
		} else
			return true;
		return false;
	}

	protected boolean isImage(int i, int j) {
		// TODO Auto-generated method stub

		for (ImageMosaicMatrix m2 : outputMatrix.getMosaicList()) {
			if (j - m2.getY() >= 0 && j - m2.getY() < m2.getHeight()
					&& i - m2.getX() >= 0 && i - m2.getX() < m2.getWidth())
				if (m2.getMatrix()[j - m2.getY()][i - m2.getX()].type == Mosaic.IMAGE) {
					return true;

				}
		}
		return false;
	}

}
